/*
 * @Author: Clark
 * @Email: haixuanwoTxh@gmail.com
 * @Date: 2022-03-09 21:10:25
 * @LastEditors: Clark
 * @LastEditTime: 2022-05-25 11:03:56
 * @Description: file content
 */

#ifndef SOCKET_H
#define SOCKET_H

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string>

#define PORT 8888

// typedef enum{
//     TCP,
//     UDP,
// }tcpOrUdp_t;

typedef enum{
    SERVER,
    CLIENT,
}serverOrClient_t;

class Socket
{
public:
    Socket(std::string &IP, unsigned short port, serverOrClient_t serverOrClient)
    {
        this->IP = IP;
        this->port = port;
        this->serverOrClient = serverOrClient;
        serverSocketFd = -1;
        clientSocketFd = -1;
    }

    bool init()
    {
        serverSocketFd = socket(AF_INET, SOCK_STREAM, 0);
        if (serverSocketFd < 0)
        {
            perror("socket error");
            return false;
        }

        if (SERVER == serverOrClient)
        {
            struct sockaddr_in serverAddr;
            bzero(&serverAddr, sizeof(serverAddr));
            serverAddr.sin_family = AF_INET;
            serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
            serverAddr.sin_port = htons(port);

            int ret = bind(serverSocketFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
            if (ret < 0)
            {
                perror("bind error");
                return false;
            }

            ret = listen(serverSocketFd, 10);
            if (ret < 0)
            {
                perror("listen error");
                return false;
            }

            printf("server run\n");
        }

        return true;
    }

    bool accept_client()
    {
        clientSocketFd = accept(serverSocketFd, (struct sockaddr*)nullptr, nullptr);
        if (clientSocketFd < 0)
        {
            printf("accept error\n");
            return false;
        }
        return true;
    }

    bool connect_server()
    {
        struct sockaddr_in serverAddr;
        bzero(&serverAddr, sizeof(serverAddr));
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(port);
        if (inet_pton(AF_INET, IP.c_str(), &serverAddr.sin_addr) <= 0)
        {
            printf("inet_pton error\n");
            return false;
        }

        if (connect(serverSocketFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0)
        {
            perror("connect error\n");
            return false;
        }

        return true;
    }

    int get_client_fd()
    {
        return clientSocketFd;
    }

    int read_socket(char *buf, int bufSize)
    {
        if (SERVER == serverOrClient)
        {
            return read(clientSocketFd, buf, bufSize);
        }
        else if(CLIENT == serverOrClient)
        {
            return read(serverSocketFd, buf, bufSize);
        }

        return -1;
    }

    int write_socket(char *buf, unsigned int len)
    {
        if (SERVER == serverOrClient)
        {
            if (clientSocketFd > 0)
            {
                return write(clientSocketFd, buf, len);
            }
        }
        else if(CLIENT == serverOrClient)
        {
            if (serverSocketFd > 0)
            {
                return write(serverSocketFd, buf, len);
            }
        }

        return -1;
    }

    ~Socket()
    {
        close(clientSocketFd);
        close(serverSocketFd);
    }
private:
    std::string IP;
    unsigned short port;
    int serverSocketFd;
    int clientSocketFd;
    serverOrClient_t serverOrClient;
};

#endif
